﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Muel.TypeScriptFacade.Core
{
    public class TypeScriptModule
    {
        private string name;
        private TypeScriptModule parentModule;
        private TypeScriptObjectManager manager;
        private List<TypeScriptModule> submodules = new List<TypeScriptModule>();
        private List<TypeScriptType> objects = new List<TypeScriptType>();

        public TypeScriptModule(TypeScriptObjectManager manager, string name)
            : this(manager, null, name)
        { }

        public TypeScriptModule(TypeScriptObjectManager manager, TypeScriptModule parentModule, string name)
        {
            this.manager = manager;
            this.parentModule = parentModule;
            if (this.parentModule != null)
            {
                this.parentModule.AddSubModule(this);
            }
            this.name = name;
        }

        public string Name { get { return name; } }
        
        private string ns = null;
        public string Namespace
        {
            get
            {
                if (string.IsNullOrEmpty(ns))
                {
                    if (ParentModule != null)
                    {
                        ns = string.Format("{0}.{1}", ParentModule.Namespace, this.Name);
                    }
                    else
                    {
                        ns = Name;
                    }
                }
                return ns;
            }
        }

        public TypeScriptModule ParentModule { get { return parentModule; } }
        public TypeScriptModule[] SubModules { get { return this.submodules.ToArray(); } }
        public TypeScriptType[] Objects { get { return this.objects.ToArray(); } }

        protected void AddSubModule(TypeScriptModule module)
        {
            this.submodules.Add(module);
        }

        internal void AddObject(TypeScriptType obj)
        {
            this.objects.Add(obj);
        }

        public override string ToString()
        {
            return this.Namespace;
        }

        public bool IsTopLevel { get { return ParentModule == null; } }


        #region Output to TypeScript

        private string moduleFormat = @"
{0}module {1} {{
{2}
}}";
        internal string ToTypeScript(int nestingDepth)
        {
            string moduleInternals =
                string.Join(Environment.NewLine, this.SubModules.Select(module => module.ToTypeScript(nestingDepth))) +
                string.Join(Environment.NewLine, this.Objects.Where(obj => obj.NestingDepth == nestingDepth && !obj.IsArray && !obj.IsPrimitiveBased).Select(obj => obj.ToTypeScript()));

            string moduleExport = this.IsTopLevel ? string.Empty : "export ";

            return string.Format(moduleFormat, moduleExport, this.Name, moduleInternals);
        }

        #endregion
    }
}
